package com.titanrise.crm.environment.ioc;

import com.titanrise.crm.common.constants.ApplicationConstant;
import com.titanrise.crm.environment.annotation.*;
import com.titanrise.crm.environment.orm.MapperFactory;
import com.titanrise.crm.environment.annotation.Mapper;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description: 项目单例模式配置
 * @Author: pront
 * @Time:2024-11-02 11:44
 */

public class SingletonConfig {

    /**
     * 单例池
     */
    public static final Map<String, Object> singletonPool = new HashMap<>();

    private static Boolean isInitialized = false;

    private static List<Object> instantceList = new ArrayList<>();

    private static final Map<String, Object> mapperList = new HashMap<>();

    private static boolean status = false;

    public static void initSingletonPool(String packageName) {
        if (!isInitialized) {
            isInitialized = true;
            singletonPool.put("applicationConstant", new ApplicationConstant());
            scanAndRegisterBeans(packageName);
        }
    }

    /**
     * 扫描并注册Bean
     *
     * @param packageName 包名
     */
    private static void scanAndRegisterBeans(String packageName) {
        try {
            // 获取包下所有类
            Set<Class<?>> classes = ClassScanner.getClasses(packageName);
            for (Class<?> clazz : classes) {
                if (isRightAnnotation(clazz) && !clazz.isInterface() && !clazz.isAnnotation()) {
                    // 创建实例并注册到单例池中
                    Object instance = clazz.getDeclaredConstructor().newInstance();
                    boolean flag = injectDependencies(instance, true);  // 尝试注入依赖
                    String key = getBeanKey(clazz);
                    if (flag) {
                        singletonPool.put(key, instance);
                    }
                }
                // 标注了 @Mapper 注解，加入 mapperList
                if (clazz.isInterface() && clazz.isAnnotationPresent(Mapper.class)) {
                    String key = getBeanKey(clazz);
                    mapperList.put(key, clazz);  // 将接口放入 mapperList，稍后处理
                }
            }
            registerMappers();
            while(!instantceList.isEmpty()) reInjectDependencies();
//            System.out.println(singletonPool.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void reInjectDependencies() {
        List<Object> toRemove = new ArrayList<>();
        for (Object instance : instantceList) {
            status = false;
            injectDependencies(instance, false);
            if (status) {
                String key = getBeanKey(instance.getClass());
                singletonPool.put(key, instance);
                toRemove.add(instance); // 注册了删除
            }
        }
        instantceList.removeAll(toRemove);
    }

    private static void registerMappers() {
        for (Map.Entry<String, Object> entry : mapperList.entrySet()) {
            // 利用 MapperFactory 创建代理对象
            Object mapperInstance = MapperFactory.getMapper((Class<?>) entry.getValue());
            singletonPool.put(entry.getKey(), mapperInstance);
        }
        mapperList.clear();
    }

    /**
     * Autowired 依赖注入
     *
     * @param instance 实例对象
     */
    private static boolean injectDependencies(Object instance, boolean flag) {
        Field[] fields = instance.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Autowired.class)) {
                // 获取字段的类型
                Class<?> fieldType = field.getType();
                Object dependency = getBean(fieldType);  // 从单例池中获取依赖项

                if (dependency != null) {
                    field.setAccessible(true);
                    if (!flag) status = true;
                    try {
                        field.set(instance, dependency);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 若依赖未找到，延迟注入 第一次
                    if (flag) instantceList.add(instance);
                    else {
                    }
                    return false;
                }
            }
        }
        return true;
    }

    private static boolean isRightAnnotation(Class<?> clazz) {
        return clazz.isAnnotationPresent(Component.class) ||
                clazz.isAnnotationPresent(Controller.class) ||
                clazz.isAnnotationPresent(Service.class) ||
                clazz.isAnnotationPresent(Configuration.class) ||
                clazz.isAnnotationPresent(Repository.class) ||
                clazz.isAnnotationPresent(Mapper.class);
    }

    /**
     * 获取 Bean 的键，如果对应注解有 value 属性则返回该值，否则返回类名首字母小写形式
     *
     * @param clazz 类型type
     * @return as spring bean name
     */
    private static String getBeanKey(Class<?> clazz) {
        if (clazz.isAnnotationPresent(Service.class)) {
            String value = clazz.getAnnotation(Service.class).value();
            if (!value.isEmpty()) {
                return value; // 使用 @Service 的 value
            }
        } else if (clazz.isAnnotationPresent(Controller.class)) {
            String value = clazz.getAnnotation(Controller.class).beanName();
            if (!value.isEmpty()) {
                return value; // 使用 @Controller 的 value
            }
        } else if (clazz.isAnnotationPresent(Component.class)) {
            String value = clazz.getAnnotation(Component.class).value();
            if (!value.isEmpty()) {
                return value; // 使用 @Component 的 value
            }
        } else if (clazz.isAnnotationPresent(Configuration.class)) {
            String value = clazz.getAnnotation(Configuration.class).value();
            if (!value.isEmpty()) {
                return value; // 使用 @Configuration 的 value
            }
        } else if (clazz.isAnnotationPresent(Repository.class)) {
            String value = clazz.getAnnotation(Repository.class).value();
            if (!value.isEmpty()) {
                return value;
            }
        } else if (clazz.isAnnotationPresent(Mapper.class)) {
            String value = clazz.getAnnotation(Mapper.class).value();
            if (!value.isEmpty()) {
                return value;
            }
        }

        // 返回类名首字母小写形式
        return Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
    }

    /**
     * 根据名称获取
     *
     * @param name bean name
     * @return bean
     */
    public static Object getBean(String name) {
        Object bean = singletonPool.get(name);
        if (bean != null) return bean;
        try {
            // 获取 name 对应的类
            Class<?> clazz = Class.forName(name);
            // 检查是否有符合的接口实现
            for (Object instance : singletonPool.values()) {
                if (clazz.isAssignableFrom(instance.getClass())) {
                    return instance;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T getBean(Class<T> clazz) {
        // 首先尝试通过类名获取
        String key = Character.toLowerCase(clazz.getSimpleName().charAt(0)) + clazz.getSimpleName().substring(1);
        T bean = clazz.cast(singletonPool.get(key));
        if (bean == null) {
            // 如果未找到，则尝试通过接口名获取
            for (Map.Entry<String, Object> entry : singletonPool.entrySet()) {
                if (clazz.isAssignableFrom(entry.getValue().getClass())) {
                    return clazz.cast(entry.getValue());
                }
            }
        }
        return bean;
    }


}
